Skip to content

Display availability statements when relevant#408

Open
matt-bernhardt wants to merge 11 commits into
mainfrom
use-599
Open

Display availability statements when relevant#408
matt-bernhardt wants to merge 11 commits into
mainfrom
use-599

Conversation

@matt-bernhardt

@matt-bernhardt matt-bernhardt commented Jun 15, 2026

Copy link
Copy Markdown
Member

This integrates the recently-added AlmaSru model with the UI, restoring the availability statements for users to see. This involves:

  1. Defining a lookup route /almasru which invokes the lookup method
  2. Adding a _trigger pattern on the Primo result partial that will invoke this lookup route when needed

In service of these goals, a few other changes get introduced:

  1. The content loader stimulus controller gets added support for lazy loading, which gets activated by adding data-content-loader-lazy-loading-value="" to the tag which calls the controller.
  2. The AlmaSru model gets its validation and extraction logic altered, so that there is an externally-callable valid_alma_id?() method. The UI leverages this to make sure we only ask for this lookup when the ID seems relevant (there's no way to know from just an identifier whether a record will actually have an availability block - but we can tell when a record comes from Alma).

Side effects:

  • The guard clauses around this integration are a little inconsistent at the moment. I don't think any of the calculations are horribly inefficient, so I think it's probably fine - but I'd welcome some specific attention on this point.
  • The "enabled?" method on AlmaSru gets renamed from .alma_sru_enabled? to just .enabled?
  • I alphabetized the lookup routes in config/routes.rb

Developer

Accessibility
  • ANDI or WAVE has been run in accordance to our guide.
  • This PR contains no changes to the view layer.
  • New issues flagged by ANDI or WAVE have been resolved.
  • New issues flagged by ANDI or WAVE have been ticketed (link in the Pull Request details above).
  • No new accessibility issues have been flagged.
New ENV
  • All new ENV is documented in README.
  • All new ENV has been added to Heroku Pipeline, Staging and Prod.
  • ENV has not changed.
Approval beyond code review
  • UXWS/stakeholder approval has been confirmed.
  • UXWS/stakeholder review will be completed retroactively.
  • UXWS/stakeholder review is not needed.
Additional context needed to review

Do searches in the review app (or when running locally), and watch the network traffic in your dev tools. You should see lazy-loading happening, and you should only see this happening for records with Alma docIDs. This should happen across tabs.

Code Reviewer

Code
  • I have confirmed that the code works as intended.
  • Any CodeClimate issues have been fixed or confirmed as
    added technical debt.
Documentation
  • The commit message is clear and follows our guidelines
    (not just this pull request message).
  • The documentation has been updated or is unnecessary.
  • New dependencies are appropriate or there were no changes.
Testing
  • There are appropriate tests covering any new functionality.
  • No additional test coverage is required.

@coveralls

coveralls commented Jun 15, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 27801626200

Coverage increased (+0.003%) to 98.356%

Details

  • Coverage increased (+0.003%) from the base build.
  • Patch coverage: 39 of 39 lines across 3 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 1521
Covered Lines: 1496
Line Coverage: 98.36%
Coverage Strength: 70.71 hits per line

💛 - Coveralls

@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 15, 2026 20:57 Inactive
@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 15, 2026 23:01 Inactive
@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 16, 2026 19:05 Inactive
@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 16, 2026 20:53 Inactive
@qltysh

qltysh Bot commented Jun 16, 2026

Copy link
Copy Markdown

❌ 9 blocking issues (10 total)

Tool Category Rule Count
rubocop Style Line is too long. [147/120] 5
rubocop Lint Method has too many lines. [16/10] 2
rubocop Lint Class has too many lines. [111/100] 1
rubocop Lint Assignment Branch Condition size for format\_availability is too high. [<2, 21, 3> 21.31/17] 1
qlty Structure Function with high complexity (count = 5): lookup 1

@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 17, 2026 19:50 Inactive
Comment thread app/models/alma_sru.rb Outdated
Comment thread app/models/alma_sru.rb Outdated
Comment thread test/models/alma_sru_test.rb
@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 17, 2026 20:04 Inactive
@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 17, 2026 20:15 Inactive
@matt-bernhardt matt-bernhardt marked this pull request as ready for review June 17, 2026 20:16
@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 18, 2026 16:53 Inactive
@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 18, 2026 17:24 Inactive
This will be loaded via Stimulus when needed in a subsequent commit.

Alma SRU controller tests
This still needs to be filtered, most likely (tho the AlmaSru model
will also do its own filtering)
This involves adding lazy-loading support to the content loader
controller, which may be a feature that other async calls would
benefit from.
- Also adds additional filter on UI invoking this path, leveraging new validation method
** Why are these changes being introduced:

Rather than render multiple availability statements, we want to just
show the first, with a suffix phrase of "and other locations" if there
are more locations.

** Relevant ticket(s):

* https://mitlibraries.atlassian.net/browse/use-599

** How does this address that need:

This slightly refactors the formatting logic for handling the statements
after they've been formatted. All blocks are formatted to start with,
and then if there are multiple statements we append the suffix. Only the
first statement is ever returned, as a list of one entry - so the
overall contract of the .lookup() method is unchanged.

** Document any side effects to this change:

It is a bit inefficient to format records that we then discard. I'm
not sure that this will be a significant issue, but it should be noted.
** Why are these changes being introduced:

Up until now, the availability statements have been empty links - but
we want them to go to the full records view, and specifically to the
locations block of that page.

** Relevant ticket(s):

* https://mitlibraries.atlassian.net/browse/use-599

** How does this address that need:

This calls the new PrimoLinkBuilder's full_record_link method, and adds
the `getit_link1_0` document fragment to send the user to the list of
available locations.

** Document any side effects to this change:

There are two concerns to note here:
1. The document fragment we are using feels fragile, and like it may
go away in the future. I also haven't checked what the fragment is for
NDE.
2. This link is _very_ similar to the full record link that appears
immediately before this in the UI. It will likely pass an accessibility
check because it is not identical - but this feels like a technicality,
and not an ideal user experience. I'm choosing to propose this anyway to
see if I'm alone in thinking this - I can live with it, but it would not
take much for me to support an alternative.
** Why are these changes being introduced:

Our previous implementation of the availability statements had some nice
features like icons and bold styling for location names. We want to
carry this forward, but want to keep the model-level implementation for
this formatting.

** Relevant ticket(s):

* https://mitlibraries.atlassian.net/browse/use-599

** How does this address that need:

This removes the availability() and location() record helpers, and
reintroduces those features within the AlmaSru model. This includes the
status handling logic of the previous implementation.

** Document any side effects to this change:

Other parts of the application rely on the icon() helper in the record
helper model, so we can't remove that here. As a result, there is now a
duplication of that logic in two places in the application, which isn't
ideal.

Avoiding this would mean changing where the AlmaSru model formats its
output, which I'd rather not do at this point - but I'm open to feedback
about this during code review.
@mitlib mitlib temporarily deployed to timdex-ui-pi-use-599-ivehx6dtf June 18, 2026 23:57 Inactive
Comment thread app/models/alma_sru.rb
else
Rails.logger.error("Unhandled availability status: #{status}")
"#{_icon('question')} Uncertain availability (#{status.humanize}) in "
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method has too many lines. [11/10] [rubocop:Metrics/MethodLength]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method has one construct - the case statement for building message text based on the item's status. I'm not sure how this can be made shorter, except for maybe dropping the error handling for the unexpected branch - but I'm not certain that's a good idea.

I am open to another way of handling an unexpected status - maybe a Sentry exception would be more appropriate - but this would still result in a method of the same length.


assert_equal(['Available at Rotch Library Stacks (NA680.C25 2007)'], result)
assert_equal(
["<i class='fa-sharp fa-solid fa-check' aria-hidden='true'></i> Available in <strong>Rotch Library</strong> Stacks (NA680.C25 2007)"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line is too long. [142/120] [rubocop:Layout/LineLength]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the assertion, I'm not sure that this is something I'm willing to change. For this test specifically, maybe the full message text isn't necessary (see the following test and its assertions).


assert_equal('Echo at quebec charlie (delta)', AlmaSru.format_availability(ava_hash))
assert_equal(
"<i class='fa-sharp fa-solid fa-check' aria-hidden='true'></i> Available in <strong>quebec</strong> charlie (delta)",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line is too long. [123/120] [rubocop:Layout/LineLength]

@matt-bernhardt matt-bernhardt Jun 19, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first of three assertions that pins down the full format for the availability message. As such, I'm not sure I'm willing to use less than the full content of the message here. I'm open to counter arguments from a person on this, but the linter alone isn't a big enough signal. If preferred, I'm happy to disable/re-enable this check for this line, however.

}

assert_equal(
"<i class='fa-sharp fa-solid fa-times' aria-hidden='true'></i> Not currently available in <strong>quebec</strong>",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line is too long. [121/120] [rubocop:Layout/LineLength]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the second of three assertions that pins down the full format for the availability message. As such, I'm not sure I'm willing to use less than the full content of the message here. I'm open to counter arguments from a person on this, but the linter alone isn't a big enough signal. If preferred, I'm happy to disable/re-enable this check for this line, however.


assert_equal('Echo at quebec', AlmaSru.format_availability(ava_hash))
assert_equal(
"<i class='fa-sharp fa-solid fa-question' aria-hidden='true'></i> Uncertain availability (Echo) in <strong>quebec</strong>",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line is too long. [130/120] [rubocop:Layout/LineLength]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the third of three assertions that pins down the full format for the availability message. As such, I'm not sure I'm willing to use less than the full content of the message here. I'm open to counter arguments from a person on this, but the linter alone isn't a big enough signal. If preferred, I'm happy to disable/re-enable this check for this line, however.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores display of availability statements for Primo (Alma) records by adding an /almasru lookup endpoint backed by the AlmaSru model, then lazy-loading those statements into the Primo result UI via the existing content-loader Stimulus controller.

Changes:

  • Added AlmaController#sru and a new /almasru route to return availability HTML for a given Alma doc ID.
  • Replaced Primo API-derived availability rendering with an Alma SRU-triggered lazy-load mechanism in the Primo result partial.
  • Extended content_loader_controller.js with optional IntersectionObserver-based lazy loading, and refactored AlmaSru validation/extraction + availability formatting.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
test/models/normalize_primo_record_test.rb Removes tests for Primo-normalized availability fields that are no longer produced.
test/models/alma_sru_test.rb Updates SRU formatting/validation tests to match new HTML-based statements and valid_alma_id?.
test/helpers/record_helper_test.rb Removes tests for the deleted availability helper behavior.
test/controllers/alma_controller_test.rb Adds integration tests for the new /almasru endpoint (but currently has broken status assertions).
config/routes.rb Adds /almasru route and reorders lookup routes.
app/views/search/_trigger_almasru.html.erb Adds a new content-loader trigger partial for Alma SRU availability.
app/views/search/_result_primo.html.erb Uses AlmaSru.valid_alma_id? to decide when to render the SRU trigger.
app/views/alma/sru.html.erb Adds the endpoint’s HTML view rendering availability statements.
app/models/normalize_primo_record.rb Stops emitting :availability and :other_availability in normalized Primo records.
app/models/alma_sru.rb Renames .alma_sru_enabled? to .enabled?, adds valid_alma_id?/extract_alma_id, changes formatting, collapses multiple AVA entries.
app/javascript/controllers/content_loader_controller.js Adds lazyLoading value + IntersectionObserver support.
app/helpers/record_helper.rb Removes the availability/location helpers; leaves icon helper (currently generating invalid HTML).
app/controllers/alma_controller.rb Introduces the controller action serving SRU availability HTML without layout.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/views/alma/sru.html.erb Outdated
Comment thread app/models/alma_sru.rb Outdated
Comment thread app/models/alma_sru.rb
Comment on lines 153 to 160
@@ -151,6 +159,37 @@ def self.alma_sru_enabled?
true
end

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is addressed (perhaps not resolved entirely) in the next commit

Comment thread app/views/search/_result_primo.html.erb
Comment thread app/views/search/_trigger_almasru.html.erb Outdated
Comment thread test/controllers/alma_controller_test.rb Outdated
Comment thread test/controllers/alma_controller_test.rb Outdated
Comment thread test/controllers/alma_controller_test.rb Outdated
Comment thread test/controllers/alma_controller_test.rb Outdated
Comment thread test/controllers/alma_controller_test.rb Outdated
Update test and teardown for AlmaSru.enabled?

Update result_get? check to include Alma ID format

We've removed the availability, so that cause and test were
meaningless.
Comment thread app/models/alma_sru.rb
phrase = "#{_phrase_start(ERB::Util.html_escape(availability['e'].to_s))} <strong>#{ERB::Util.html_escape(availability['q'].to_s)}</strong> " \
"#{ERB::Util.html_escape(availability['c'].to_s)}".squish
phrase += " (#{ERB::Util.html_escape(availability['d'].to_s)})" if availability['d'].present?
phrase

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assignment Branch Condition size for format_availability is too high. [<2, 21, 3> 21.31/17] [rubocop:Metrics/AbcSize]

Comment thread app/models/alma_sru.rb
phrase = "#{availability['e']&.humanize} at #{availability['q']} #{availability['c']}".squish
phrase += " (#{availability['d']})" if availability['d'].present?

phrase = "#{_phrase_start(ERB::Util.html_escape(availability['e'].to_s))} <strong>#{ERB::Util.html_escape(availability['q'].to_s)}</strong> " \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line is too long. [147/120] [rubocop:Layout/LineLength]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants